package org.anyin.gitee.cloud.lib.core.config;

import org.anyin.gitee.cloud.lib.core.cache.CacheTemplate;
import org.anyin.gitee.cloud.lib.core.extension.DefaultExtensionHandlerFactoryImpl;
import org.anyin.gitee.cloud.lib.core.extension.IExtensionHandlerFactory;
import org.anyin.gitee.cloud.lib.core.thread.MdcExecutor;
import org.anyin.gitee.cloud.lib.core.web.filter.RequestIdFilter;
import org.anyin.gitee.cloud.lib.core.web.filter.WebContextFilter;
import org.anyin.gitee.cloud.lib.core.web.serializer.Jackson2ObjectMapperBuilderCustomizer_;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;

public abstract class DefaultAppConfig{

    private static final Integer DEFAULT_THREAD_CORE_POOL_SIZE = 10;
    private static final Integer DEFAULT_THREAD_MAX_POOL_SIZE  = 100;
    private static final Integer DEFAULT_THREAD_QUEUE_CAPACITY  = 200;

    public Integer getThreadCorePoolSize() {
        return DEFAULT_THREAD_CORE_POOL_SIZE;
    }

    public Integer getThreadMaxPoolSize() {
        return DEFAULT_THREAD_MAX_POOL_SIZE;
    }

    public Integer getThreadQueueCapacity() {
        return DEFAULT_THREAD_QUEUE_CAPACITY;
    }

    /**
     * 统一线程池配置
     * 使用MdcExecutor包装，避免request-id 丢失
     */
    @Bean
    @ConditionalOnMissingBean
    public Executor executor(){
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(getThreadCorePoolSize());
        executor.setMaxPoolSize(getThreadMaxPoolSize());
        executor.setQueueCapacity(getThreadQueueCapacity());
        executor.setThreadNamePrefix("AsyncExecutorThread-");
        //超过最大队列,使用当前线程执行,也就是原本异步的会变为同步
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return new MdcExecutor(executor);
    }
    /**
     * redis 缓存
     */
    @Bean
    public CacheTemplate cacheTemplate(StringRedisTemplate stringRedisTemplate) throws Exception{
        CacheTemplate cacheTemplate = new CacheTemplate();
        cacheTemplate.setStringRedisTemplate(stringRedisTemplate);
        cacheTemplate.afterPropertiesSet();
        return cacheTemplate;
    }

    /**
     * 扩展点配置
     */
    @Bean
    public IExtensionHandlerFactory extensionHandlerFactory(){
        return new DefaultExtensionHandlerFactoryImpl();
    }

    /**
     * web context
     */
    @Bean
    @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
    public FilterRegistrationBean<WebContextFilter> webContextFilter(){
        FilterRegistrationBean<WebContextFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new WebContextFilter());
        registrationBean.setName("webContextFilter");
        registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
        return registrationBean;
    }

    /**
     * request id
     */
    @Bean
    @ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
    public FilterRegistrationBean<RequestIdFilter> requestIdFilter(){
        FilterRegistrationBean<RequestIdFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new RequestIdFilter());
        registrationBean.setName("requestIdFilter");
        registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE + 1);
        return registrationBean;
    }

    @Bean
    public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer(){
        // 解决前端Long形式丢失的问题
        return new Jackson2ObjectMapperBuilderCustomizer_();
    }
}
